﻿namespace BattleCity.GameLogic

open System
open FMath
open UI
open Types
open Casanova
open Microsoft.Xna.Framework

module GameState =

 let blockSize = 4.0<m>
 let bulletSize = blockSize * 0.25

 //Usate per determinare quando effettuare il play dei suoni
 let playerShoot = ref false;
 let enemyDestroyed = ref false;
 let playerDestroyed = ref false;
 let playerSpawn = ref true;
 let bonusCatched = ref false;

 //Variabili per il blinking dello scudo quando attivato
 let shieldEnabled = ref false;
 let shieldClock = ref 0.0<s>

 //Stato di gioco iniziale del carro del giocatore
 let playerTank =
  {
    Direction = Vector2<1>.Up
    Position = Vector2<m>(0.0<m>,24.0<m>)
    Velocity = 0.0<m/s>
    WheelRollTheta = 0.0
    CollisionSquare = Square(Vector2<m>(0.0<m>,20.0<m>), 3.9<m>)
    TankType = PlayerTank
    IsStealth = false
    Bonus = None
    Weapon = SingleBullet
  }

 //Stato di gioco globale 
 let mutable gameState =
  {
    BlockGrid = createEmptyMap blockSize 13.0
    BulletList = Variable(fun () -> [])
    EnemiesBulletList = Variable(fun () -> [])
    PlayerTank = Variable(fun () -> playerTank)
    PlayerState = ref PlayerState.Spawning
    PlayerTransitionClock = ref 0.0<s>
    EnemiesList = Variable(fun () -> [])
    DestroyedEnemiesList = Variable(fun () -> [])
    SpawnedEnemiesList = Variable(fun () -> [])
    BonusList = Variable(fun () -> [])
    SpawnedBonus = ref []
    PlayerLives = ref 0
    DestroyedEnemies = ref 0
    GeneratedEnemies = ref 0
    ChangedBlockList = ref []
    HittedEnemiesList = ref []
    VariableCounter = Casanova.variable_counter
    CompletedLevels = ref 0
  } 

 let levelNumber = ref 0
 let bannerOnScreen = ref false
 let startEndLevelClock = ref 0.0<s>
 let turnList : ref<List<int>> = ref []
 let levelEnemyList : ref<List<(Types.EnemyType * Types.Bonus)>> = ref [ ];

 let loadEnemiesList (list) =
  levelEnemyList.Value <- [  for element in list do
                              yield element
                          ]

 let blockMapSize = sqrt(gameState.BlockGrid.Length |> float) - 1.0 |> int
 let mapBounding = blockSize * 6.0
 let tankBulletBoundingDistance = (blockSize - (blockSize * 0.5)) * (blockSize - (blockSize * 0.5))
 
 let enemyStartSlotsPos = [| gameState.BlockGrid.[0,0].position; gameState.BlockGrid.[0,6].position; gameState.BlockGrid.[0,12].position; 
                             gameState.BlockGrid.[12,0].position; gameState.BlockGrid.[12,12].position |]

 let wheelRadius = 0.8<m>

 let CreateTankState (direction : Vector2<1>, position : Vector2<m>, velocity : float<m/s>,  
                      wheelRollTheta : float, tankType: TankType, isStealth: bool, bonus : Bonus, weapon : WeaponType) =
  let tankState =
   {
    Direction = direction
    Position = position
    Velocity = velocity
    WheelRollTheta = wheelRollTheta
    CollisionSquare = Square(position, 2.8<m>)
    TankType = tankType
    IsStealth = isStealth
    Bonus = bonus
    Weapon = weapon
   }
  tankState

 let CreateBulletState (position : Vector2<m>, velocity : float<m/s>, direction: Vector2<1>, pow : int) =
  let bulletState = 
    {
        position = Variable (fun () -> position)
        collisionSquare = Variable(fun () -> Square((position), bulletSize))
        velocity = variable(30.0<m/s>)
        direction = direction
        intersection = Variable(fun () -> (NoCollision , NoCollision))
        power = pow
    }

  bulletState

 let loadGameState (playerTank: Tank, 
                    playerLives: int,
                    completedLevels: int,
                    playerState: PlayerState,
                    playerTransitionClock: float<s>,
                    generatedEnemies: int,
                    destroyedEnemies: int,
                    destroyedEnList : System.Collections.Generic.List<Tuple<Tank,float<s>>>,
                    spawnedEnList : System.Collections.Generic.List<Tuple<Tank,float<s>>>,
                    enList : System.Collections.Generic.List<Tank>,
                    bnList : System.Collections.Generic.List<Tuple<Bonus,FMath.Vector2<m>,float<s>>>,
                    blockMap : BlockMakeUp[,]) = 

  let enemiesList = [ for enTank in enList do yield Variable(fun () -> enTank) ]
  let spawnedEnemiesList = [ for enTank in spawnedEnList do yield (enTank.Item1, enTank.Item2) ]
  let destroyedEnemiesList = [ for enTank in destroyedEnList do yield (enTank.Item1, enTank.Item2) ]
  let bonusList = [ for bonus in bnList do yield (bonus.Item1, bonus.Item2, bonus.Item3) ]

  gameState.PlayerTransitionClock.Value <- playerTransitionClock 
  gameState.PlayerState.Value <- playerState
  gameState.GeneratedEnemies.Value <- generatedEnemies
  gameState.DestroyedEnemies.Value <- destroyedEnemies

  let newGameState =
   {
    BlockGrid = createBlockMap blockSize blockMap
    BulletList = Variable(fun () -> [])
    EnemiesBulletList = Variable(fun () -> [])
    PlayerTank = Variable(fun () -> playerTank) //OK
    PlayerState = gameState.PlayerState //OK
    PlayerTransitionClock = gameState.PlayerTransitionClock //OK
    EnemiesList = Variable(fun () -> enemiesList) //OK
    DestroyedEnemiesList = Variable(fun () -> destroyedEnemiesList) //OK
    SpawnedEnemiesList = Variable(fun () -> spawnedEnemiesList) //OK
    BonusList = Variable(fun () -> bonusList) //OK
    SpawnedBonus = ref []
    PlayerLives = ref playerLives
    DestroyedEnemies = gameState.DestroyedEnemies //OK
    GeneratedEnemies = gameState.GeneratedEnemies //OK
    ChangedBlockList = ref []
    HittedEnemiesList = ref []
    VariableCounter = gameState.VariableCounter
    CompletedLevels = ref completedLevels
   } 
  newGameState